#include "stdafx.h"
#include "fuBitmapButton.h"

#include <wx/dc.h>
#include <wx/dcclient.h>
#include <wx/image.h>
#include <wx/settings.h>

IMPLEMENT_DYNAMIC_CLASS(fuBitmapButton, wxWindow)

BEGIN_EVENT_TABLE(fuBitmapButton, wxWindow)
EVT_MOUSE_EVENTS(fuBitmapButton::OnMouseEvent)
EVT_PAINT(fuBitmapButton::OnPaint)
EVT_SIZE(fuBitmapButton::OnSizeEvent)
EVT_ERASE_BACKGROUND(fuBitmapButton::OnEraseBackground)
END_EVENT_TABLE()

#define wxMB_COLOR_OVER     wxColour(0xE8,0xE8,0xE8)
#define wxMB_COLOR_BG       wxColour(0xD7,0xD7,0xD7)
#define wxMB_TEXT_MARGIN    8
#define wxMB_EVENT          wxEVT_COMMAND_BUTTON_CLICKED

//////////////////////////////////////////////////////////////////////////
fuBitmapButton::fuBitmapButton(wxWindow *parent, 
                               wxWindowID id,
                               const wxBitmap& bitmap,
                               const wxPoint& pos /*= wxDefaultPosition*/, 
                               const wxSize& size /*= wxDefaultSize*/,
                               long /*style*/ /*= wxBU_AUTODRAW*/, 
                               const wxValidator& /*validator*/ /*= wxDefaultValidator*/,
                               const wxString& /*name*/ /*= wxButtonNameStr*/) :
wxWindow(parent, id, pos, size)
{
    if(size == wxDefaultSize) {
        m_width = bitmap.GetSize().x;
        m_height = bitmap.GetSize().y;
    }
    else {
        m_width = size.x;
        m_height = size.y;
    }

    m_state = State_ButtonUp;
    m_enabled = true;
    m_painted = false;
    m_theme = true;

    memset(m_icons,0,sizeof(m_icons));

    if(bitmap.IsOk()){
        m_icons[State_ButtonUp] = new wxIcon;
        m_icons[State_ButtonDis] = new wxIcon;

        m_icons[State_ButtonUp]->CopyFromBitmap(bitmap);
        m_icons[State_ButtonDis]->CopyFromBitmap(bitmap);
    }

    // button font text
#ifdef __WIN32__
    m_font = new wxFont(8,wxDEFAULT,wxNORMAL,wxBOLD);
#else
    m_font = new wxFont(10,wxDEFAULT,wxNORMAL,wxBOLD);
#endif    
    m_laststate = State_ButtonNew;

    // use the up icon dimensions for the image
    int x = 0;
    if(m_icons[0]) x = m_icons[0]->GetWidth();
    if(x <= m_width) m_dx = (m_width - x) >> 1;
    else m_dx = 0;
    m_dy = 0;

    SetSize(m_width,m_height);
    m_bitmap = new wxBitmap(m_width,m_height);
}

fuBitmapButton::~fuBitmapButton()
{
    for(int i=0;i<4;i++) {
        if(m_icons[i]) delete m_icons[i];
    }
    delete m_bitmap;
    delete m_font;
};

void fuBitmapButton::DrawBorder(wxDC& dc, BorderType border)
{
    if(!m_theme) {
        wxColour bg = GetParent()->GetBackgroundColour();
        wxBrush brush_over(wxMB_COLOR_OVER,wxSOLID);
        dc.SetBrush(brush_over);
        dc.SetPen(*wxTRANSPARENT_PEN);
        dc.DrawRectangle(0,0,m_width,m_height);
    }
    wxPen light(wxColour(0xFF,0xFF,0xFF),1,wxSOLID);
    wxPen dark(wxColour(0x80,0x80,0x80),1,wxSOLID);
    wxPen corner(wxMB_COLOR_BG,1,wxSOLID);

    switch(border) {
    case Border_High:
        dc.SetPen(light);
        dc.DrawLine(1,0,m_width-2,0);
        dc.DrawLine(0,1,0,m_height-2);
        dc.SetPen(dark);
        dc.DrawLine(0,m_height-1,m_width-1,m_height-1);
        dc.DrawLine(m_width-1,0,m_width-1,m_height-1);
        break;
    case Border_Sunken:
        dc.SetPen(dark);
        dc.DrawLine(1,0,m_width-2,0);
        dc.DrawLine(0,1,0,m_height-2);
        dc.SetPen(light);
        dc.DrawLine(1,m_height-1,m_width-2,m_height-1);
        dc.DrawLine(m_width-1,1,m_width-1,m_height-2);
        break;
    default:
        break;
    }
};

void fuBitmapButton::DrawOnBitmap()
{
    wxCoord dx = 0;
    wxCoord dy = 0;
    wxCoord w;
    wxCoord h;

    wxMemoryDC dc;
    dc.SelectObject(*m_bitmap);
    // use the system background colour for buttons (wxSYS_COLOUR_BTNFACE)
    // if there is no theme enabled
    if(!m_theme) {
        wxBrush brush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE),wxSOLID);
        wxColour bg = m_parent->GetBackgroundColour();
        dc.SetBackground(brush);
        dc.Clear();
    }
    else {
        wxBitmap bmp = GetBackgroundRegion(GetId());
        if(bmp.Ok()) {
            dc.DrawBitmap(bmp,0,0,false);
        }
    }
    dc.SetFont(*m_font);

    switch(m_state) {
    case State_ButtonUp:
        if(m_icons[m_state]) dc.DrawIcon(*m_icons[m_state],m_dx,m_dy);
        break;
    case State_ButtonOver:
        if(m_icons[m_state]) dc.DrawIcon(*m_icons[m_state],m_dx,m_dy);
        else {
            DrawBorder(dc,Border_High);
            if(m_icons[State_ButtonUp]) {
                dc.DrawIcon(*m_icons[State_ButtonUp],m_dx,m_dy);
            }
        }
        break;
    case State_ButtonDown:
        if(m_icons[m_state]) dc.DrawIcon(*m_icons[m_state],m_dx,m_dy);
        else {
            DrawBorder(dc,Border_Sunken);
            if(m_icons[State_ButtonUp]) {
                dc.DrawIcon(*m_icons[State_ButtonUp],m_dx+1,m_dy+1);
            }
        }
        dx = dy = 1;
        break;
    case State_ButtonDis:
        if(m_icons[m_state]) dc.DrawIcon(*m_icons[m_state],m_dx,m_dy);
        else {
        }
        break;
    default:
        dc.SelectObject(wxNullBitmap);
        return;
    }

    dc.GetTextExtent(m_text,&w,&h);
    if(w > m_width) w = m_width;
    if(h > m_height) h = m_height;

    if(!m_text.IsEmpty()) {
        if(m_enabled) {
            dc.SetTextForeground(wxColour(0,0,0));
            dc.DrawText(m_text,((m_width-w)>>1)+1+dx,m_height-h+dy);
        }
        else {
            dc.SetTextForeground(wxColour(255,255,255));
            dc.DrawText(m_text,((m_width-w)>>1)+1+dx,m_height-h+dy);
            dc.SetTextForeground(wxColour(128,128,128));
            dc.DrawText(m_text,((m_width-w)>>1)+dy,m_height-h-1+dy);
        }
    }

    dc.SelectObject(wxNullBitmap);
};

void fuBitmapButton::OnPaint(wxPaintEvent& WXUNUSED(event))
{
    wxPaintDC dc(this);
    if(!m_painted) {
        DrawOnBitmap();
        m_painted = true;
    }
    dc.DrawBitmap(*m_bitmap,0,0,false);
};

void fuBitmapButton::OnEraseBackground(wxEraseEvent& event)
{
#ifdef __WXMSW__
    Redraw();
    event.Skip();
#else
    // at this time, the background image isn't repaint by the toolbar,
    // so defer the redraw for later
    wxSizeEvent ev(GetSize(),GetId());
    AddPendingEvent(ev);
    event.Skip();
#endif
};

void fuBitmapButton::OnMouseEvent(wxMouseEvent& event)
{
    if(!m_enabled) return;

    wxCommandEvent ev(wxMB_EVENT,GetId());
    ev.SetEventObject(this);

    if(event.ButtonDown()) {
        m_state = State_ButtonDown;
        Redraw();
    }
    else if(event.ButtonUp()) {
        m_state = State_ButtonOver;
        wxPoint pos = event.GetPosition();
        if((pos.x < GetSize().GetWidth()) && 
            (pos.y < GetSize().GetHeight())) {
                GetParent()->GetEventHandler()->ProcessEvent(ev);
        }
        Redraw();
    }
    else if (event.Entering()) {
        m_state = State_ButtonOver;
        Redraw();
        return;
    }
    else if(event.Leaving()) {
        if((m_state == State_ButtonOver) || (m_state == State_ButtonDown)) {
            m_state = State_ButtonUp;
            Redraw();
            return;
        }
    }
};

void fuBitmapButton::OnSizeEvent(wxSizeEvent &event)
{
    Redraw();
    event.Skip();
};

void fuBitmapButton::Enable()
{
    if(!m_enabled) {
        m_state = m_laststate;
        m_enabled = true;
        Redraw();
    }
};

bool fuBitmapButton::Enable( bool enable )
{
    if(enable) Enable();
    else Disable();
    return true;
}


void fuBitmapButton::Disable()
{
    if(m_enabled) {
        m_laststate = m_state;
        m_enabled = false;
        m_state = State_ButtonDis;
        Redraw();
    }
};

bool fuBitmapButton::Press()
{
    if(m_state != State_ButtonDown) {
        m_state = State_ButtonDown;
        Redraw();
        return true;
    }
    return false;
};

void fuBitmapButton::Redraw()
{
    if(m_painted) {    
        DrawOnBitmap();
        wxClientDC dc(this);
        dc.DrawBitmap(*m_bitmap,0,0,false);
    }
};

bool fuBitmapButton::Release()
{
    if(m_state == State_ButtonDown) {
        m_state = State_ButtonUp;
        Redraw();
        return true;
    }
    return false;
};

void fuBitmapButton::SetText(const wxChar* text)
{
    int w,h,x = 0;
    wxClientDC dc(this);
    dc.SetFont(*m_font);
    m_text = text;
    dc.GetTextExtent(text,&w,&h);
    if(w > m_width) m_width = w + wxMB_TEXT_MARGIN;
    m_height += m_font->GetPointSize()+2;
    SetSize(m_width,m_height);

    if(m_icons[0]) x = m_icons[0]->GetWidth();
    if(x <= m_width) m_dx = (m_width - x) >> 1;
    else m_dx = 0;

    m_bitmap->Create(m_width,m_height);
    Redraw();
};

void fuBitmapButton::SetBitmapLabel( const wxBitmap& bitmap )
{
    if(bitmap.IsOk()){
        if(m_icons[State_ButtonUp])
            delete m_icons[State_ButtonUp];
        m_icons[State_ButtonUp] = new wxIcon;
        m_icons[State_ButtonUp]->CopyFromBitmap(bitmap);
    }
}

void fuBitmapButton::SetBitmapSelected( const wxBitmap& bitmap )
{
    if(bitmap.IsOk()){
        if(m_icons[State_ButtonDown])
            delete m_icons[State_ButtonDown];
        m_icons[State_ButtonDown] = new wxIcon;
        m_icons[State_ButtonDown]->CopyFromBitmap(bitmap);
    }
}

void fuBitmapButton::SetBitmapFocus( const wxBitmap& bitmap )
{
    if(bitmap.IsOk()){
        if(m_icons[State_ButtonUp])
            delete m_icons[State_ButtonUp];
        m_icons[State_ButtonUp] = new wxIcon;
        m_icons[State_ButtonUp]->CopyFromBitmap(bitmap);
    }
    //m_backgroundBitmap = bitmap;
}

void fuBitmapButton::SetBitmapDisabled( const wxBitmap& bitmap )
{
    //if(bitmap.IsOk()){
    //    if(m_icons[State_ButtonDis])
    //        delete m_icons[State_ButtonDis];
    //    m_icons[State_ButtonDis] = new wxIcon;
    //    m_icons[State_ButtonDis]->CopyFromBitmap(bitmap);
    //}
    m_backgroundBitmap = bitmap;
}

void fuBitmapButton::SetBitmapHover( const wxBitmap& bitmap )
{
    if(bitmap.IsOk()){
        if(m_icons[State_ButtonOver])
            delete m_icons[State_ButtonOver];
        m_icons[State_ButtonOver] = new wxIcon;
        m_icons[State_ButtonOver]->CopyFromBitmap(bitmap);
    }
}

wxBitmap fuBitmapButton::GetBackgroundRegion(int id)
{
    int x,y,w,h;
    this->GetSize(&w,&h);
    this->GetPosition(&x,&y);
    // background clipping
    wxRect r = GetParent()->GetRect();
    int dx = (r.x + r.width) - x;
    if(dx < w) w = dx;
    if(w > 0) return m_backgroundBitmap.GetSubBitmap(wxRect(x,y,w,h));
    return wxNullBitmap;
};

//BEGIN_EVENT_TABLE(fuCheckButton, fuBitmapButton)
//EVT_MOUSE_EVENTS(fuCheckButton::OnMouseEvent)
//END_EVENT_TABLE()
//
//void fuCheckButton::OnMouseEvent(wxMouseEvent & event)
//{
//    if(!m_enabled) return;
//
//    wxCommandEvent ev(wxMB_EVENT,GetId());
//    ev.SetEventObject(this);
//
//    if(event.ButtonDown()) {
//        m_state = State_ButtonDown;
//        Redraw();
//    }
//    else if(event.ButtonUp()) {
//        wxPoint pos = event.GetPosition();
//        if((pos.x < GetSize().GetWidth()) && 
//            (pos.y < GetSize().GetHeight())) {
//                // mouse up must inside button range, toggle internal state
//                m_snapin ^= true;
//                if(m_snapin) m_state = State_ButtonDown;
//                else m_state = State_ButtonOver;
//                // set it in the event
//                ev.SetInt(m_snapin);
//                // and send it to the parent
//                GetParent()->GetEventHandler()->ProcessEvent(ev);
//                Redraw();
//        }
//    }
//    else if (event.Entering()) {
//        // do not redraw ButtonOver state if button is pressed
//        if(m_snapin) return;
//        m_state = State_ButtonOver;
//        Redraw();
//        return;
//    }
//    else if(event.Leaving()) {
//        // do not redraw ButtonOver state if button is pressed
//        if(m_snapin) return;
//        if((m_state == State_ButtonOver) || (m_state == State_ButtonDown)) {
//            m_state = State_ButtonUp;
//            Redraw();
//            return;
//        }
//    }
//};
//
//bool fuCheckButton::Press()
//{
//    bool result = false;
//    if((result = fuBitmapButton::Press()) == true) {
//        m_snapin = true;
//    }
//    return result;
//};
//
//bool fuCheckButton::Release()
//{
//    bool result = false;
//    if((result = fuBitmapButton::Release()) == true) {
//        m_snapin = false;
//    }
//    return result;
//};
//
//BEGIN_EVENT_TABLE(fuRadioButton, fuBitmapButton)
//EVT_MOUSE_EVENTS(fuRadioButton::OnMouseEvent)
//END_EVENT_TABLE()
//
//fuRadioButton::fuRadioButton(wxWindow * parent, wxWindowID id,
//                               const wxPoint & pos,
//                               const wxSize & size,
//                               char **upXPM,char **overXPM,
//                               char **downXPM,char **disXPM,
//                               fuRadioButtonBox* selectBox) :
//fuCheckButton(parent,id,pos,size,upXPM,overXPM,downXPM,disXPM)
//{
//    m_box = selectBox; 
//    if(m_box) m_box->Add(this);
//};
//
//void fuRadioButton::OnMouseEvent(wxMouseEvent & event)
//{
//    if(!m_enabled) return;
//    if(m_snapin) return;
//
//    wxCommandEvent ev(wxMB_EVENT,GetId());
//    ev.SetEventObject(this);
//
//    if(event.ButtonDown()) {
//        m_state = State_ButtonDown;
//        Redraw();
//    }
//    else if(event.ButtonUp()) {
//        wxPoint pos = event.GetPosition();
//        if((pos.x < GetSize().GetWidth()) && 
//            (pos.y < GetSize().GetHeight())) {
//                // mouse up must inside button range, toggle internal state
//                m_snapin ^= true;
//
//                if(m_snapin) {
//                    if(m_box) m_box->ReleaseAll();
//                    m_snapin = true;
//                }
//                if(m_snapin) m_state = State_ButtonDown;
//                else m_state = State_ButtonOver;
//
//                // send it to the parent
//                GetParent()->GetEventHandler()->ProcessEvent(ev);
//                Redraw();
//        }
//    }
//    else if (event.Entering()) {
//        m_state = State_ButtonOver;
//        Redraw();
//        return;
//    }
//    else if(event.Leaving()) {
//        if((m_state == State_ButtonOver) || (m_state == State_ButtonDown)) {
//            m_state = State_ButtonUp;
//            Redraw();
//            return;
//        }
//    }
//};
//
//BEGIN_EVENT_TABLE(fuSeparator, fuBitmapButton)
//EVT_ERASE_BACKGROUND(fuSeparator::OnEraseBackground)
//END_EVENT_TABLE()
//
//void fuSeparator::DrawOnBitmap()
//{
//    wxMemoryDC dc;
//    dc.SelectObject(*m_bitmap);
//
//    if(!m_theme) {
//        wxBrush brush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE),wxSOLID);
//        dc.SetBackground(brush);
//        dc.Clear();
//    }
//    else {
//        fuToolbar* mtb = wxDynamicCast(GetParent(),fuToolbar);
//        if(mtb) {
//            wxBitmap bmp = mtb->GetBackgroundRegion(GetId());
//            if(bmp.Ok()) {
//                dc.DrawBitmap(bmp,0,0,false);
//            }
//        }
//    }
//    dc.SetPen(*wxLIGHT_GREY_PEN);
//    // separator is a vertical relief line
//    dc.DrawLine(m_width>>1,1,m_width>>1,m_height-3);
//    dc.SetPen(*wxMEDIUM_GREY_PEN);
//    dc.DrawLine((m_width>>1)+1,2,(m_width>>1)+1,m_height-2);
//};
